﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Visitor;

namespace ASTClass
{
    class RelExprAST : AST
    {
        public RelExprAST() : base() { name = "RelExpr"; }
        public RelExprAST(AST parent) : base(parent) { name = "RelExpr"; }

        public override AST Clone()
        {
            RelExprAST ast = new RelExprAST();
            ast.operators = operators;
            foreach (AST c in children)
                ast.children.Add(c.Clone());

            return ast;
        }

        #region Visitor pattern

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }

        #endregion Visitor pattern

        public override void CodeGen(Taste.SymbolTable st, Taste.CodeFileGen cfg)
        {
            int i = 0;
            children[i].CodeGen(st, cfg);
            foreach (Operator op in Operators)
            {
                children[++i].CodeGen(st, cfg);

                cfg.AddCommand("lw", "$v0, 0($sp)");
                cfg.AddCommand("addiu", "$sp, $sp, 4");
                cfg.AddCommand("move", "$t1, $v0");
                cfg.AddCommand("lw", "$v0, 0($sp)");
                cfg.AddCommand("addiu", "$sp, $sp, 4");
                cfg.AddCommand("move", "$t0, $v0");

                if (op.Equals(Operator.Equal))
                {
                    cfg.AddCommand("beq", "$t0, $t1, _RelOp" + this.UniqueName);
                    cfg.AddCommand("li", "$a0, 0");
                    cfg.AddCommand("j", "_endRelOp" + this.UniqueName);
                    cfg.AddFuncName("_RelOp" + this.UniqueName);
                    cfg.AddCommand("li", "$a0, 1");
                    cfg.AddFuncName("_endRelOp" + this.UniqueName);
                }
                if (op.Equals(Operator.Greater))
                {
                    cfg.AddCommand("slt", "$a0, $t1, $t0");
                }
                if (op.Equals(Operator.Less))
                {
                    cfg.AddCommand("slt", "$a0, $t0, $t1");
                }
                if (op.Equals(Operator.GreaterEqual))
                {
                    cfg.AddCommand("sub", "$t1, $t1, 1");
                    cfg.AddCommand("slt", "$a0, $t1, $t0");
                }
                if (op.Equals(Operator.LessEqual))
                {
                    cfg.AddCommand("add", "$t1, $t1, 1");
                    cfg.AddCommand("slt", "$a0, $t0, $t1");  
                }
                if (op.Equals(Operator.NotEqual))
                {
                    cfg.AddCommand("bne", "$t0, $t1, _RelOp" + this.UniqueName);
                    cfg.AddCommand("li", "$a0, 0");
                    cfg.AddCommand("j", "_endRelOp" + this.UniqueName);
                    cfg.AddFuncName("_RelOp" + this.UniqueName);
                    cfg.AddCommand("li", "$a0, 1");
                    cfg.AddFuncName("_endRelOp" + this.UniqueName); 
                }

                cfg.AddCommand("subu", "$sp, $sp, 4");
                cfg.AddCommand("sw", "$a0, 0($sp)");
            }
        }
    }
}
